#include <iostream>

#include <vector> //循环队列 模拟
#include "SemModule.hpp"
#include <semaphore.h> //信号量 头文件

#include <unistd.h>

namespace Souce
{
    template <class T>
    class Sou
    {
    private:
        std::vector<T> _queue; // 内部循环变量 22(队列开辟大小)
        size_t _capacity;      // 总的容量 22（初始化）
        int _head;             // 消费者的位置
        int _tail;             // 生产者的位置

        SemModule::Sem _spacesem; // 生产者信号量c
        SemModule::Sem _datasem;  // 消费者信号量  //不是 如果信号量
        // 消费者 出队列 头指针进 数据P操作（减少信号量） 空间V操作（增加信号量）
        // 生产者 进队列 尾指针进 数据V操作（增加信号量） 空间P操作（减少信号量）
        // 理解： 消耗掉了，可以放的空间变多了消费者的空间(v操作)
    public:
        Sou(int _out_cap) : _capacity(_out_cap), _queue(_out_cap), _head(0), _tail(0), _spacesem(_out_cap), _datasem(0)
        {
        }
        ~Sou()
        {
            // 信号量销毁
            if (::sem_destroy(&_spacesem._sem) != 0) // 成功返回0
            {
                std::cout << "生产者信号量销毁失败！" << std::endl;
            }
            if (::sem_destroy(&_datasem._sem) != 0) // 成功返回0
            {
                std::cout << "消费者信号量销毁失败！" << std::endl;
            }
        }

        void Equeue(const T &_out_data) // 入队列
        {
            // 这里是生产者
            _spacesem.P();

            _queue[_tail] = _out_data;
            _tail++;
            _tail %= _capacity;

            _datasem.V(); // 生产一个数据多一个 空间少一个
        }

        void Pop(T *_out_data)
        {
            // 这里是消费者
            _datasem.P();

            *_out_data = _queue[_head];
            _head++;
            _head %= _capacity;

            _spacesem.V();
        }
    };

}

void *Consumer(void *_argv) // 消费者 P操作 消耗资源
{
    Souce::Sou<int> *_buffer = static_cast<Souce::Sou<int> *>(_argv);
    while (true)
    {
        sleep(2);
        int _data = 0;
        _buffer->Pop(&_data);
        std::cout << "取出数据: " << _data << " " << std::endl;
    }
}

void *Productor(void *_argv) // 生产者 V操作
{
    Souce::Sou<int> *_buffer = static_cast<Souce::Sou<int> *>(_argv);

    // 生产数据 变量
    int _data = 0;

    // 生产数据
    while (true)
    {
        sleep(1);
        _buffer->Equeue(_data);
        std::cout << "生产了一个数据：" << _data++ << std::endl;
    }
}

int main()
{
    //>> 创建一个共享资源
    Souce::Sou<int> *_buffer = new Souce::Sou<int>(5);

    //>> 创建线程变量
    pthread_t _pt1;
    pthread_t _pt2;

    pthread_create(&_pt1, nullptr, Consumer, _buffer);
    pthread_create(&_pt2, nullptr, Productor, _buffer);

    pthread_join(_pt1, nullptr);
    pthread_join(_pt2, nullptr);

    return 0;
}